package main

import (
	"bufio"
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"syscall"
	"time"
	"unsafe"

	"navidog/config"
	"navidog/db"
	"navidog/watcher"

	"encoding/json"

	"regexp"
	"strconv"

	"github.com/fsnotify/fsnotify"
	"github.com/pingcap/tidb/pkg/parser"
	"github.com/pingcap/tidb/pkg/parser/ast"
	"github.com/pingcap/tidb/pkg/parser/format"
)

// Windows API 常量
const (
	STD_OUTPUT_HANDLE                  = ^uintptr(0) - 10 - 1
	ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
	ENABLE_PROCESSED_OUTPUT            = 0x0001
)

// Windows API 函数
var (
	kernel32           = syscall.NewLazyDLL("kernel32.dll")
	procGetStdHandle   = kernel32.NewProc("GetStdHandle")
	procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
	procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
)

// 启用Windows控制台ANSI支持
func enableWindowsANSI() bool {
	if runtime.GOOS != "windows" {
		return true
	}

	// 检查是否在Git Bash或其他支持ANSI的终端
	if isGitBash() {
		return true
	}

	handle, _, _ := procGetStdHandle.Call(STD_OUTPUT_HANDLE)
	if handle == ^uintptr(0) {
		return false
	}

	var mode uint32
	ret, _, _ := procGetConsoleMode.Call(handle, uintptr(unsafe.Pointer(&mode)))
	if ret == 0 {
		return false
	}

	mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT
	ret, _, _ = procSetConsoleMode.Call(handle, uintptr(mode))
	return ret != 0
}

// 检测是否在Git Bash环境
func isGitBash() bool {
	// 检查环境变量
	if term := os.Getenv("TERM"); term != "" && term != "dumb" {
		return true // Git Bash 会设置 TERM 环境变量
	}
	if msystem := os.Getenv("MSYSTEM"); msystem != "" {
		return true // Git Bash/MSYS2 会设置 MSYSTEM
	}
	if shell := os.Getenv("SHELL"); strings.Contains(shell, "bash") {
		return true
	}
	// 检查ConEmu和其他终端
	if os.Getenv("ConEmuPID") != "" || os.Getenv("WT_SESSION") != "" {
		return true
	}
	return false
}

// ANSI 颜色代码
const (
	Reset  = "\033[0m"
	Bold   = "\033[1m"
	Italic = "\033[3m"

	// 霓虹灯颜色
	Cyan    = "\033[96m"
	Magenta = "\033[95m"
	Yellow  = "\033[93m"
	Green   = "\033[92m"
	Blue    = "\033[94m"
	Red     = "\033[91m"

	// 光效
	Bright = "\033[1;97m"
	Glow   = "\033[5m"
)

// 全局变量控制是否使用ANSI
var useANSI = false

// 安全的颜色输出
func colorize(color, text string) string {
	if useANSI {
		return color + text + Reset
	}
	return text
}

// 清屏并显示LOGO
func displayLogo() {
	if useANSI {
		// 清屏
		fmt.Print("\033[2J")
		// 移动光标到顶部
		fmt.Print("\033[H")

		// 使用直接的颜色代码而不是colorize函数
		fmt.Printf("\n")
		fmt.Printf("    %s%s███╗   ██╗ █████╗ ██╗   ██╗██╗██████╗  ██████╗  ██████╗%s\n", Magenta, Bold, Reset)
		fmt.Printf("    %s%s████╗  ██║██╔══██╗██║   ██║██║██╔══██╗██╔═══██╗██╔════╝%s\n", Yellow, Bold, Reset)
		fmt.Printf("    %s%s██╔██╗ ██║███████║██║   ██║██║██║  ██║██║   ██║██║  ███╗%s\n", Green, Bold, Reset)
		fmt.Printf("    %s%s██║╚██╗██║██╔══██║╚██╗ ██╔╝██║██║  ██║██║   ██║██║   ██║%s\n", Blue, Bold, Reset)
		fmt.Printf("    %s%s██║ ╚████║██║  ██║ ╚████╔╝ ██║██████╔╝╚██████╔╝╚██████╔╝%s\n", Red, Bold, Reset)
		fmt.Printf("    %s%s╚═╝  ╚═══╝╚═╝  ╚═╝  ╚═══╝  ╚═╝╚═════╝  ╚═════╝  ╚═════╝%s\n", Bright, Bold, Reset)
		fmt.Printf("\n")
		fmt.Printf("                           %s%s✨ 智能数据库管理工具 ✨%s\n", Magenta, Bold, Reset)
		fmt.Printf("\n")
		fmt.Printf("%s%s状态栏: %s%s正在启动...%s\n", Bold, Green, Reset, Yellow, Reset)
		fmt.Printf("%s━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━%s\n", Cyan, Reset)
	} else {
		// Fallback 纯文本版本
		fmt.Println()
		fmt.Println("    ███╗   ██╗ █████╗ ██╗   ██╗██╗██████╗  ██████╗  ██████╗")
		fmt.Println("    ████╗  ██║██╔══██╗██║   ██║██║██╔══██╗██╔═══██╗██╔════╝")
		fmt.Println("    ██╔██╗ ██║███████║██║   ██║██║██║  ██║██║   ██║██║  ███╗")
		fmt.Println("    ██║╚██╗██║██╔══██║╚██╗ ██╔╝██║██║  ██║██║   ██║██║   ██║")
		fmt.Println("    ██║ ╚████║██║  ██║ ╚████╔╝ ██║██████╔╝╚██████╔╝╚██████╔╝")
		fmt.Println("    ╚═╝  ╚═══╝╚═╝  ╚═╝  ╚═══╝  ╚═╝╚═════╝  ╚═════╝  ╚═════╝ ")
		fmt.Println()
		fmt.Println("                           *** 智能数据库管理工具 ***")
		fmt.Println()
		fmt.Println("状态栏: 正在启动...")
		fmt.Println("________________________________________________________________________________")
	}
}

// 更新状态栏
func updateStatus(message string) {
	if useANSI {
		// 保存当前光标位置
		fmt.Print("\033[s")
		// 移动到状态栏位置（第11行）
		fmt.Print("\033[11;1H")
		// 清除该行
		fmt.Print("\033[K")
		fmt.Printf("%s%s状态栏: %s%s%s%s", Bold, Green, Reset, Yellow, message, Reset)
		// 恢复光标位置
		fmt.Print("\033[u")
	} else {
		fmt.Printf("状态: %s\n", message)
	}
}

// 日志输出函数，确保不覆盖LOGO
var logLineCounter = 0

const maxLogLines = 9 // 日志区域最多显示9行

func logOutput(message string) {
	if useANSI {
		// 计算当前日志行位置（第13-21行）
		currentLine := 13 + (logLineCounter % maxLogLines)

		// 移动到指定行并清除该行
		fmt.Printf("\033[%d;1H\033[K", currentLine)

		// 输出日志
		fmt.Printf("%s[%s]%s %s", Green, time.Now().Format("15:04:05"), Reset, message)

		logLineCounter++

		// 如果超过最大行数，清除最老的日志行
		if logLineCounter >= maxLogLines {
			// 清除下一行（即将被覆盖的最老日志）
			nextLine := 13 + (logLineCounter % maxLogLines)
			fmt.Printf("\033[%d;1H\033[K", nextLine)
		}

		// 保持光标在命令输入区域（动态底部）
		showPrompt()
	} else {
		// 简单的文本输出
		fmt.Printf("[%s] %s\n", time.Now().Format("15:04:05"), message)
		fmt.Print("> ")
	}
}

// 自定义日志writer
type CustomLogWriter struct{}

func (w *CustomLogWriter) Write(p []byte) (n int, err error) {
	message := strings.TrimSpace(string(p))
	if message != "" {
		logOutput(message)
	}
	return len(p), nil
}

// Global variables for managing workers
var globalCtx context.Context
var globalCancel context.CancelFunc
var globalWg sync.WaitGroup
var globalActiveWorkers int
var globalConfigs []config.Config
var globalWatchers map[string]*watcher.Watcher

// Global slice to track lock files created by this process
var globalLockFiles []string

// ===== 翻页功能 =====
type LastQueryInfo struct {
	FilePath string // query.sql 绝对路径
	SQL      string // 完整 SQL
	Limit    int
	Offset   int
}

var lastQuery LastQueryInfo
var lastQueryMu sync.Mutex

func main() {
	configFile := flag.String("c", "config.json", "配置文件路径")
	flag.Parse()

	// 启用Windows控制台ANSI支持
	useANSI = enableWindowsANSI()

	// 设置自定义日志输出
	log.SetOutput(&CustomLogWriter{})
	log.SetFlags(0) // 移除默认的时间戳

	// 显示LOGO
	displayLogo()
	time.Sleep(1 * time.Second)

	programWorkDir, _ := os.Getwd()
	cfgPath := filepath.Join(programWorkDir, *configFile)
	configs, err := config.LoadConfig(cfgPath)
	if err != nil {
		updateStatus(fmt.Sprintf("❌ 加载配置文件失败: %v", err))
		log.Fatalf("加载配置文件失败: %v", err)
	}

	if len(configs) > 0 && configs[0].LogDir != "" {
		db.SetGlobalLogDir(configs[0].LogDir)
	}

	updateStatus("✅ 配置文件加载成功")

	// 创建根context和取消函数
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// 创建退出信号通道
	exitChan := make(chan bool, 1)

	// Initialize global variables
	globalConfigs = configs
	globalCtx, globalCancel = ctx, cancel
	globalActiveWorkers = 0
	globalWatchers = make(map[string]*watcher.Watcher)

	var wg sync.WaitGroup
	activeWorkers := 0

	for _, cfg := range configs {
		if !cfg.Enable {
			continue
		}
		wg.Add(1)
		activeWorkers++
		go func(c config.Config) {
			defer wg.Done()
			// 正常启动时需要检查lock文件
			if err := startWorker(ctx, c); err != nil {
				log.Printf("工作进程失败, 数据库: %s, 错误: %v", c.Database, err)
			}
		}(cfg)
	}

	updateStatus(fmt.Sprintf("🚀 已启动 %d 个工作进程", activeWorkers))
	log.Println("Navidog 已启动，正在监控所有已配置的项目...")

	// 启动命令行界面
	go func() {
		showPrompt()

		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			input := strings.TrimSpace(scanner.Text())
			if handleCommand(input, cancel, exitChan) {
				return // 退出命令处理循环
			}

			if useANSI {
				// 重新显示输入提示
				showPrompt()
			} else {
				fmt.Print("> ")
			}
		}
	}()

	// 监听系统信号和退出信号
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)

	select {
	case <-sigCh:
		updateStatus("🛑 收到系统信号，正在关闭...")
		log.Println("收到系统信号，正在关闭 Navidog...")
	case <-exitChan:
		updateStatus("🛑 用户请求退出，正在关闭...")
		log.Println("用户请求退出，正在关闭 Navidog...")
	}

	// 取消所有worker的context
	cancel()

	// 等待所有worker优雅关闭，设置超时
	done := make(chan struct{})
	go func() {
		wg.Wait()
		close(done)
	}()

	select {
	case <-done:
		updateStatus("✅ 所有工作进程已优雅关闭")
		log.Println("所有工作进程已优雅关闭")
	case <-time.After(10 * time.Second):
		updateStatus("⚠️ 等待超时，强制退出")
		log.Println("等待超时，强制退出")
	}

	// 删除由本进程创建的所有锁文件
	for _, lf := range globalLockFiles {
		_ = removeLockFile(lf)
	}

	// 恢复正常终端
	if useANSI {
		fmt.Print("\033[2J\033[H")
	} else {
		fmt.Println()
		fmt.Println("================================================================================")
	}
	fmt.Println("感谢使用 Navidog! 👋")
}

// 表过滤函数：根据搜索条件过滤并创建表文件夹
func filterAndCreateTables(cfg config.Config, searchTerms []string) (int, error) {
	workDir := cfg.WorkDir
	tablesDir := filepath.Join(workDir, "tables")

	// Remove existing tables directory
	if err := os.RemoveAll(tablesDir); err != nil {
		return 0, fmt.Errorf("清空目录失败: %w", err)
	}

	// Create new tables directory
	if err := os.MkdirAll(tablesDir, 0755); err != nil {
		return 0, fmt.Errorf("创建目录失败: %w", err)
	}

	matchedCount := 0
	databaseType := cfg.DatabaseType
	if databaseType == "" {
		databaseType = "mysql"
	}

	switch databaseType {
	case "mysql":
		// Connect to MySQL and get filtered tables
		var dbClient *db.DB
		var err error

		// 检查是否启用SSH连接
		if cfg.SSH != nil && cfg.SSH.Enable {
			dbClient, err = db.NewWithSSH(*cfg.SSH, cfg.Host, cfg.Port, cfg.User, cfg.Password, cfg.Database, true)
		} else {
			dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true",
				cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Database)
			dbClient, err = db.NewWithReadOnly(dsn, true) // Use read-only for safety
		}
		if err != nil {
			return 0, fmt.Errorf("连接MySQL失败: %w", err)
		}
		defer dbClient.Close()

		// Get all tables and filter
		allTables, err := dbClient.GetTables(cfg.IncludeTablePatterns, cfg.ExcludeTablePatterns)
		if err != nil {
			return 0, fmt.Errorf("获取表列表失败: %w", err)
		}

		// Filter tables containing all search terms
		for _, table := range allTables {
			if matchesAllTerms(table, searchTerms) {
				tableDir := filepath.Join(tablesDir, table)
				if err := os.MkdirAll(tableDir, 0755); err != nil {
					continue
				}

				// Create query.sql
				querySQLPath := filepath.Join(tableDir, "query.sql")
				queryContent := fmt.Sprintf("SELECT * FROM `%s` LIMIT 100;", table)
				os.WriteFile(querySQLPath, []byte(queryContent), 0644)

				logOutput(fmt.Sprintf("✅ 保留匹配的表: %s", table))
				matchedCount++
			}
		}

	case "bigquery":
		// Handle BigQuery with multiple datasets
		authProjectID := cfg.ProjectID
		dataProjectID := cfg.Database
		if dataProjectID == "" {
			dataProjectID = authProjectID
		}

		// Get all datasets
		allDatasets := cfg.Datasets
		if cfg.Dataset != "" && !contains(allDatasets, cfg.Dataset) {
			allDatasets = append(allDatasets, cfg.Dataset)
		}

		for _, dataset := range allDatasets {
			// Connect to BigQuery
			dbClient, err := db.NewBigQuery(authProjectID, dataProjectID, dataset, cfg.CredentialsFile, true, cfg.ProxyURL)
			if err != nil {
				logOutput(fmt.Sprintf("❌ 连接BigQuery失败 (%s): %v", dataset, err))
				continue
			}

			// Get all tables for this dataset and filter
			allTables, err := dbClient.GetTables(cfg.IncludeTablePatterns, cfg.ExcludeTablePatterns)
			if err != nil {
				logOutput(fmt.Sprintf("❌ 获取表列表失败 (%s): %v", dataset, err))
				dbClient.Close()
				continue
			}

			// Filter tables containing all search terms
			datasetHasMatches := false
			for _, table := range allTables {
				if matchesAllTerms(table, searchTerms) {
					// Create dataset directory if not exists
					datasetDir := filepath.Join(tablesDir, dataset)
					if !datasetHasMatches {
						os.MkdirAll(datasetDir, 0755)
						datasetHasMatches = true
					}

					// Create table directory
					tableDir := filepath.Join(datasetDir, table)
					if err := os.MkdirAll(tableDir, 0755); err != nil {
						continue
					}

					// Create query.sql
					querySQLPath := filepath.Join(tableDir, "query.sql")
					queryContent := fmt.Sprintf("SELECT * FROM `%s.%s.%s` LIMIT 100", dataProjectID, dataset, table)
					os.WriteFile(querySQLPath, []byte(queryContent), 0644)

					logOutput(fmt.Sprintf("✅ 保留匹配的表: %s.%s", dataset, table))
					matchedCount++
				}
			}
			dbClient.Close()
		}
	}

	return matchedCount, nil
}

// 检查表名是否匹配所有搜索条件
func matchesAllTerms(tableName string, searchTerms []string) bool {
	if len(searchTerms) == 0 {
		return true // 没有搜索条件时匹配所有
	}

	lowerTableName := strings.ToLower(tableName)
	for _, term := range searchTerms {
		if !strings.Contains(lowerTableName, strings.ToLower(term)) {
			return false // 如果任何一个条件不匹配，返回false
		}
	}
	return true // 所有条件都匹配
}

// 初始化表文件（启动时调用，或reload时调用）
func initializeTablesForWorker(cfg config.Config, searchTerms []string) error {
	workDir := cfg.WorkDir

	if len(searchTerms) > 0 {
		// 有搜索条件时，使用过滤逻辑
		_, err := filterAndCreateTables(cfg, searchTerms)
		return err
	} else {
		// 没有搜索条件时，使用标准初始化
		databaseType := cfg.DatabaseType
		if databaseType == "" {
			databaseType = "mysql"
		}

		switch databaseType {
		case "mysql":
			var dbClient *db.DB
			var err error

			// 检查是否启用SSH连接
			if cfg.SSH != nil && cfg.SSH.Enable {
				dbClient, err = db.NewWithSSH(*cfg.SSH, cfg.Host, cfg.Port, cfg.User, cfg.Password, cfg.Database, cfg.ReadOnlyMode)
			} else {
				dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true",
					cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Database)
				dbClient, err = db.NewWithReadOnly(dsn, cfg.ReadOnlyMode)
			}
			if err != nil {
				return fmt.Errorf("连接MySQL数据库失败: %w", err)
			}
			defer dbClient.Close()

			return dbClient.InitializeTableFiles(workDir, cfg.IncludeTablePatterns, cfg.ExcludeTablePatterns)

		case "bigquery":
			authProjectID := cfg.ProjectID
			dataProjectID := cfg.Database
			if dataProjectID == "" {
				dataProjectID = authProjectID
			}

			allDatasets := cfg.Datasets
			if cfg.Dataset != "" && !contains(allDatasets, cfg.Dataset) {
				allDatasets = append(allDatasets, cfg.Dataset)
			}

			for _, dataset := range allDatasets {
				dbClient, err := db.NewBigQuery(authProjectID, dataProjectID, dataset, cfg.CredentialsFile, cfg.ReadOnlyMode, cfg.ProxyURL)
				if err != nil {
					return fmt.Errorf("连接BigQuery失败 (%s): %w", dataset, err)
				}

				if err := dbClient.InitializeTableFiles(workDir, cfg.IncludeTablePatterns, cfg.ExcludeTablePatterns); err != nil {
					dbClient.Close()
					return fmt.Errorf("初始化表文件失败 (%s): %w", dataset, err)
				}
				dbClient.Close()
			}
		}

		return nil
	}
}

// 辅助函数：检查字符串切片是否包含指定项
func contains(slice []string, item string) bool {
	for _, s := range slice {
		if s == item {
			return true
		}
	}
	return false
}

// -------------------- 翻页辅助 --------------------
// 读取 SQL 文件，若为查询语句则记录
func recordLastQueryIfSelect(path string) {
	data, err := os.ReadFile(path)
	if err != nil {
		return
	}
	sqlText := strings.TrimSpace(string(data))
	if sqlText == "" {
		return
	}
	upper := strings.ToUpper(sqlText)
	if !(strings.HasPrefix(upper, "SELECT") || strings.HasPrefix(upper, "WITH")) {
		return // 只关心查询语句
	}
	limit, offset := parseLimitOffset(sqlText)
	lastQueryMu.Lock()
	lastQuery = LastQueryInfo{FilePath: path, SQL: sqlText, Limit: limit, Offset: offset}
	lastQueryMu.Unlock()
}

// exprToInt 尝试将表达式节点解析为整数
func exprToInt(expr ast.ExprNode) (int, bool) {
	if expr == nil {
		return 0, false
	}
	var sb strings.Builder
	// 使用 TiDB parser 的 Restore 将表达式恢复为字符串
	ctx := format.NewRestoreCtx(format.DefaultRestoreFlags, &sb)
	if err := expr.Restore(ctx); err != nil {
		return 0, false
	}
	n, err := strconv.Atoi(sb.String())
	if err != nil {
		return 0, false
	}
	return n, true
}

// 通过 TiDB Parser 解析 LIMIT / OFFSET
func parseLimitOffset(sql string) (limit, offset int) {
	limit, offset = -1, 0 // 默认值，-1 代表未设置 LIMIT

	p := parser.New()
	stmts, _, err := p.Parse(sql, "", "")
	if err != nil || len(stmts) == 0 {
		return
	}

	switch s := stmts[0].(type) {
	case *ast.SelectStmt:
		if s.Limit != nil {
			if v, ok := exprToInt(s.Limit.Count); ok {
				limit = v
			}
			if v, ok := exprToInt(s.Limit.Offset); ok {
				offset = v
			}
		}
	}

	return
}

// 生成新的带分页 SQL
func buildPagedSQL(original string, limit, offset int) string {
	semicolon := ""
	trim := strings.TrimSpace(original)
	if strings.HasSuffix(trim, ";") {
		semicolon = ";"
		trim = strings.TrimSuffix(trim, ";")
	}
	reRemove := regexp.MustCompile(`(?i)\blimit\s+\d+(\s*,\s*\d+)?(\s+offset\s+\d+)?`)
	trim = strings.TrimSpace(reRemove.ReplaceAllString(trim, ""))
	return fmt.Sprintf("%s LIMIT %d OFFSET %d%s\n", trim, limit, offset, semicolon)
}

// -------------------- Markdown -> SQL 同步 --------------------
// 如果 markdown 的 ```sql 块被修改，则将其内容同步回对应的 .sql 文件。
// 返回 true 表示已执行同步且写入了 .sql（此时无需再做 JSON diff）。
func syncSQLFromMarkdown(mdPath string) bool {
	content, err := os.ReadFile(mdPath)
	if err != nil {
		return false
	}

	text := string(content)
	start := strings.Index(text, "```sql")
	if start == -1 {
		return false
	}
	start += len("```sql")
	end := strings.Index(text[start:], "```")
	if end == -1 {
		return false
	}
	sqlBlock := strings.TrimSpace(text[start : start+end])
	if sqlBlock == "" {
		return false
	}

	// 计算对应 .sql 文件路径
	sqlPath := strings.TrimSuffix(mdPath, filepath.Ext(mdPath)) + ".sql"

	// 读取现有 sql 文件内容，比较是否已相同
	oldBytes, err := os.ReadFile(sqlPath)
	if err == nil {
		if strings.TrimSpace(string(oldBytes)) == sqlBlock {
			return false // 无需更新
		}
	}

	// 写入新 SQL
	_ = os.WriteFile(sqlPath, []byte(sqlBlock+"\n"), 0644)
	return true
}

// 全局变量存储当前的搜索条件
var globalSearchTerms []string

// 处理命令，返回true表示需要退出
func handleCommand(input string, cancel context.CancelFunc, exitChan chan bool) bool {
	// Clear current input line to prevent overlap
	if useANSI {
		fmt.Print("\033[999B\r\033[K") // move to bottom and clear line
	}
	parts := strings.Fields(input)
	if len(parts) == 0 {
		return false
	}

	command := strings.ToLower(parts[0])

	switch command {
	case "help":
		logOutput("📖 可用命令:")
		logOutput("  help   - 显示帮助信息")
		logOutput("  status - 显示系统状态")
		logOutput("  reload - 重新加载所有工作目录")
		logOutput("  find <字段1> [字段2] ... - 搜索包含所有指定字段的表文件夹")
		logOutput("  clear  - 清除日志")
		logOutput("  quit   - 退出程序")
	case "status":
		logOutput("📊 系统状态: 正常运行")
		logOutput("🔄 TiDB Parser: 已启用")
		logOutput("💾 数据库连接: 活跃")
		if useANSI {
			logOutput("🎨 ANSI 支持: 已启用")
		} else {
			logOutput("🎨 ANSI 支持: 纯文本模式")
		}
		if len(globalSearchTerms) > 0 {
			logOutput(fmt.Sprintf("🔍 当前过滤条件: %s", strings.Join(globalSearchTerms, ", ")))
		} else {
			logOutput("🔍 当前过滤条件: 无 (显示所有表)")
		}
	case "clear":
		if useANSI {
			// 清除日志区域并重置计数器
			for i := 16; i <= 24; i++ {
				fmt.Printf("\033[%d;1H\033[K", i)
			}
			logLineCounter = 0
		} else {
			// 纯文本模式下简单输出分隔线
			fmt.Println("________________________________________________________________________________")
		}
		logOutput("🧹 日志已清除")
	case "reload":
		logOutput("🔄 正在重新加载所有工作目录...")
		updateStatus("🔄 重新加载中...")
		// Clear any existing search terms for full reload
		globalSearchTerms = nil
		// Pause all watchers
		for _, w := range globalWatchers {
			w.Pause()
		}
		// Stop existing workers
		globalCancel()
		globalWg.Wait()
		// Restart workers with the same configurations (重新创建lock文件)
		globalCtx, globalCancel = context.WithCancel(context.Background())
		globalActiveWorkers = 0
		for _, cfg := range globalConfigs {
			if !cfg.Enable {
				continue
			}
			globalWg.Add(1)
			globalActiveWorkers++
			go func(c config.Config) {
				defer globalWg.Done()
				// Reload时重新创建lock文件
				if err := startWorkerWithSearchTerms(globalCtx, c, true, nil); err != nil {
					log.Printf("工作进程失败, 数据库: %s, 错误: %v", c.Database, err)
				}
			}(cfg)
		}
		// Resume all watchers
		for _, w := range globalWatchers {
			w.Resume()
		}
		updateStatus(fmt.Sprintf("🚀 已重新启动 %d 个工作进程", globalActiveWorkers))
		logOutput("✅ 重新加载完成 (已清除所有过滤条件)")
	case "find":
		if len(parts) < 2 {
			logOutput("❓ 请提供搜索字段 (用法: find <字段1> [字段2] ...)")
			return false
		}
		searchTerms := parts[1:]
		globalSearchTerms = searchTerms // 保存全局搜索条件

		logOutput(fmt.Sprintf("🔍 正在搜索包含所有字段 '%s' 的表文件夹...", strings.Join(searchTerms, "', '")))
		updateStatus("🔍 搜索中...")

		// Pause all watchers
		for _, w := range globalWatchers {
			w.Pause()
		}

		// Stop existing workers
		globalCancel()
		globalWg.Wait()

		// Filter and rebuild working directories with only matching tables
		totalFound := 0
		for _, cfg := range globalConfigs {
			if !cfg.Enable {
				continue
			}

			count, err := filterAndCreateTables(cfg, searchTerms)
			if err != nil {
				logOutput(fmt.Sprintf("❌ 处理配置 %s 时出错: %v", cfg.Database, err))
				continue
			}
			totalFound += count
		}

		if totalFound == 0 {
			logOutput("❌ 未找到匹配的表文件夹")
		}

		// Restart workers with filtered directories (不重新创建lock，因为是过滤操作)
		globalCtx, globalCancel = context.WithCancel(context.Background())
		globalActiveWorkers = 0
		for _, cfg := range globalConfigs {
			if !cfg.Enable {
				continue
			}
			globalWg.Add(1)
			globalActiveWorkers++
			go func(c config.Config) {
				defer globalWg.Done()
				// Find操作不重新创建lock文件
				if err := startWorkerWithSearchTerms(globalCtx, c, false, searchTerms); err != nil {
					log.Printf("工作进程失败, 数据库: %s, 错误: %v", c.Database, err)
				}
			}(cfg)
		}

		// Resume all watchers
		for _, w := range globalWatchers {
			w.Resume()
		}

		updateStatus(fmt.Sprintf("🚀 已重新启动 %d 个工作进程 (仅保留 %d 个匹配表)", globalActiveWorkers, totalFound))
		logOutput("✅ 搜索和过滤完成")
	case ">": // 下一页
		lastQueryMu.Lock()
		q := lastQuery
		lastQueryMu.Unlock()
		if q.FilePath == "" || q.Limit <= 0 {
			logOutput("❌ 没有可翻页的查询 (或缺少 LIMIT)")
			break
		}
		newOffset := q.Offset + q.Limit
		newSQL := buildPagedSQL(q.SQL, q.Limit, newOffset)
		if err := os.WriteFile(q.FilePath, []byte(newSQL), 0644); err != nil {
			logOutput(fmt.Sprintf("❌ 更新查询文件失败: %v", err))
			break
		}
		lastQueryMu.Lock()
		lastQuery.SQL, lastQuery.Offset = newSQL, newOffset
		lastQueryMu.Unlock()
		logOutput(fmt.Sprintf("➡️ 已切换到下一页 (offset %d)", newOffset))

	case "<": // 上一页
		lastQueryMu.Lock()
		q := lastQuery
		lastQueryMu.Unlock()
		if q.FilePath == "" || q.Limit <= 0 {
			logOutput("❌ 没有可翻页的查询 (或缺少 LIMIT)")
			break
		}
		newOffset := q.Offset - q.Limit
		if newOffset < 0 {
			newOffset = 0
		}
		newSQL := buildPagedSQL(q.SQL, q.Limit, newOffset)
		if err := os.WriteFile(q.FilePath, []byte(newSQL), 0644); err != nil {
			logOutput(fmt.Sprintf("❌ 更新查询文件失败: %v", err))
			break
		}
		lastQueryMu.Lock()
		lastQuery.SQL, lastQuery.Offset = newSQL, newOffset
		lastQueryMu.Unlock()
		logOutput(fmt.Sprintf("⬅️ 已切换到上一页 (offset %d)", newOffset))
	case "quit", "exit":
		logOutput("👋 正在退出...")
		updateStatus("🛑 用户请求退出")
		select {
		case exitChan <- true:
		default:
		}
		return true
	case "":
		// 空命令，不处理
	default:
		logOutput(fmt.Sprintf("❓ 未知命令: %s (输入 'help' 查看帮助)", input))
	}
	return false
}

func startWorker(ctx context.Context, cfg config.Config) error {
	return startWorkerWithSearchTerms(ctx, cfg, true, nil)
}

func startWorkerWithLockCheck(ctx context.Context, cfg config.Config, checkLock bool) error {
	return startWorkerWithSearchTerms(ctx, cfg, checkLock, globalSearchTerms)
}

func startWorkerWithSearchTerms(ctx context.Context, cfg config.Config, checkLock bool, searchTerms []string) error {
	log.Printf("[%s] 工作进程正在启动...", cfg.Database)

	// 获取工作目录的绝对路径
	absWorkDir, err := filepath.Abs(cfg.WorkDir)
	if err != nil {
		return fmt.Errorf("获取工作目录绝对路径失败: %w", err)
	}

	// 只在需要检查锁文件时才进行锁文件操作
	var lockFile string
	if checkLock {
		// 创建并检查锁文件
		lockFile = filepath.Join(absWorkDir, ".navidog.lock")
		if err := createLockFile(lockFile, cfg.Database); err != nil {
			return err
		}

		// Record the lock file for cleanup at program exit
		globalLockFiles = append(globalLockFiles, lockFile)
	}

	// 清空tables目录 - 无论是否LazyMode都要清空
	tablesDir := filepath.Join(absWorkDir, "tables")
	if err := os.RemoveAll(tablesDir); err != nil {
		log.Printf("[%s] 清空 tables 目录失败: %v", cfg.Database, err)
	} else {
		log.Printf("[%s] 目录已清空: %s", cfg.Database, tablesDir)
	}
	if err := os.MkdirAll(tablesDir, 0755); err != nil {
		log.Printf("[%s] 创建 tables 目录失败: %v", cfg.Database, err)
	}

	// 初始化表文件的逻辑
	shouldInitialize := false
	if !cfg.LazyMode {
		// 非LazyMode总是初始化
		shouldInitialize = true
	} else if len(searchTerms) > 0 {
		// LazyMode下，如果有搜索条件，也需要初始化（find指令）
		shouldInitialize = true
		log.Printf("[%s] LazyMode下使用find指令，需要加载对应的表", cfg.Database)
	}

	if shouldInitialize {
		if err := initializeTablesForWorker(cfg, searchTerms); err != nil {
			log.Printf("[%s] 初始化表文件时出错: %v", cfg.Database, err)
		} else {
			log.Printf("[%s] 表文件初始化完成", cfg.Database)
		}
	} else {
		log.Printf("[%s] 懒加载模式，跳过表结构初始化", cfg.Database)
	}

	// 根据数据库类型创建不同的客户端
	databaseType := cfg.DatabaseType
	if databaseType == "" {
		databaseType = "mysql" // 默认为MySQL
	}

	switch databaseType {
	case "mysql":
		return runMySQLInstance(ctx, cfg)

	case "bigquery":
		// 合并单个和多个数据集的配置
		allDatasets := cfg.Datasets
		if cfg.Dataset != "" && !contains(allDatasets, cfg.Dataset) {
			allDatasets = append(allDatasets, cfg.Dataset)
		}

		if len(allDatasets) == 0 {
			log.Printf("[%s] BigQuery配置错误: 未指定任何数据集", cfg.Database)
			return fmt.Errorf("no datasets specified for BigQuery config: %s", cfg.Database)
		}

		return runBigQueryMultiDatasets(ctx, cfg, allDatasets)

	default:
		log.Printf("[%s] 不支持的数据库类型: %s", cfg.Database, databaseType)
		return fmt.Errorf("unsupported database type: %s", databaseType)
	}
}

// createLockFile 创建锁文件，如果已存在则尝试杀死占用进程
func createLockFile(lockFilePath, instanceName string) error {
	// 确保工作目录存在
	workDir := filepath.Dir(lockFilePath)
	if err := os.MkdirAll(workDir, 0755); err != nil {
		return fmt.Errorf("创建工作目录失败: %w", err)
	}

	// 检查锁文件是否已存在
	if _, err := os.Stat(lockFilePath); err == nil {
		// 锁文件存在，读取其内容
		content, err := os.ReadFile(lockFilePath)
		if err != nil {
			return fmt.Errorf("工作目录被锁定: %s\n锁文件已存在但无法读取详细信息\n如果确认没有其他实例在运行，请手动删除锁文件: %s", workDir, lockFilePath)
		}

		var lockInfo map[string]interface{}
		if err := json.Unmarshal(content, &lockInfo); err != nil {
			return fmt.Errorf("工作目录被锁定: %s\n锁文件格式异常\n如果确认没有其他实例在运行，请手动删除锁文件: %s", workDir, lockFilePath)
		}

		// 如果是同一进程的锁，则允许复用
		if pid, ok := lockInfo["pid"].(float64); ok && int(pid) == os.Getpid() {
			// 同一进程，直接复用
			return nil
		}

		// 尝试杀死占用锁文件的进程
		if pid, ok := lockInfo["pid"].(float64); ok {
			lockPID := int(pid)
			log.Printf("[%s] 检测到锁文件被PID %d占用，尝试杀死该进程...", instanceName, lockPID)

			if killed, err := killProcess(lockPID); err != nil {
				log.Printf("[%s] 无法杀死进程 PID %d: %v", instanceName, lockPID, err)
			} else if killed {
				log.Printf("[%s] 成功杀死进程 PID %d", instanceName, lockPID)
				// 删除旧的锁文件
				if err := os.Remove(lockFilePath); err != nil {
					log.Printf("[%s] 删除旧锁文件失败: %v", instanceName, err)
				} else {
					log.Printf("[%s] 已删除旧锁文件", instanceName)
				}
			} else {
				log.Printf("[%s] 进程 PID %d 已不存在", instanceName, lockPID)
				// 进程不存在，直接删除锁文件
				if err := os.Remove(lockFilePath); err != nil {
					log.Printf("[%s] 删除旧锁文件失败: %v", instanceName, err)
				} else {
					log.Printf("[%s] 已删除无效锁文件", instanceName)
				}
			}
		} else {
			log.Printf("[%s] 锁文件中的PID格式无效", instanceName)
		}

		// 重新检查锁文件是否还存在
		if _, err := os.Stat(lockFilePath); err == nil {
			return fmt.Errorf("工作目录被锁定: %s\n"+
				"锁文件信息:\n"+
				"  PID: %v\n"+
				"  实例: %v\n"+
				"  启动时间: %v\n"+
				"  主机名: %v\n"+
				"无法自动清理锁文件，请手动删除: %s",
				workDir, lockInfo["pid"], lockInfo["instance"], lockInfo["start_time"], lockInfo["hostname"], lockFilePath)
		}
	}

	// 创建新的锁文件
	lockInfo := map[string]interface{}{
		"pid":        os.Getpid(),
		"instance":   instanceName,
		"start_time": time.Now().Format("2006-01-02 15:04:05"),
		"hostname":   getHostname(),
	}

	lockData, err := json.MarshalIndent(lockInfo, "", "  ")
	if err != nil {
		return fmt.Errorf("生成锁文件内容失败: %w", err)
	}

	if err := os.WriteFile(lockFilePath, lockData, 0644); err != nil {
		return fmt.Errorf("创建锁文件失败: %w", err)
	}

	log.Printf("[%s] 锁文件已创建: %s", instanceName, lockFilePath)
	return nil
}

// removeLockFile 删除锁文件
func removeLockFile(lockFilePath string) error {
	if _, err := os.Stat(lockFilePath); os.IsNotExist(err) {
		return nil // 文件不存在，无需删除
	}

	return os.Remove(lockFilePath)
}

// getHostname 获取主机名
func getHostname() string {
	hostname, err := os.Hostname()
	if err != nil {
		return "unknown"
	}
	return hostname
}

// killProcess 杀死指定PID的进程
func killProcess(pid int) (bool, error) {
	if pid <= 0 {
		return false, fmt.Errorf("无效的PID: %d", pid)
	}

	// 检查进程是否存在
	process, err := os.FindProcess(pid)
	if err != nil {
		// 在Unix系统上，FindProcess总是成功的，即使进程不存在
		return false, fmt.Errorf("无法找到进程: %w", err)
	}

	// 尝试发送信号0来检查进程是否存在
	if runtime.GOOS == "windows" {
		// Windows上使用不同的方法检查进程
		return killProcessWindows(pid)
	} else {
		// Unix/Linux系统
		return killProcessUnix(process)
	}
}

// killProcessUnix 在Unix/Linux系统上杀死进程
func killProcessUnix(process *os.Process) (bool, error) {
	// 首先检查进程是否存在
	if err := process.Signal(syscall.Signal(0)); err != nil {
		// 进程不存在
		return false, nil
	}

	// 尝试温和地终止进程 (SIGTERM)
	if err := process.Signal(syscall.SIGTERM); err != nil {
		return false, fmt.Errorf("无法发送SIGTERM信号: %w", err)
	}

	// 等待一段时间让进程自己退出
	time.Sleep(2 * time.Second)

	// 再次检查进程是否还存在
	if err := process.Signal(syscall.Signal(0)); err != nil {
		// 进程已退出
		return true, nil
	}

	// 如果进程仍然存在，强制杀死 (SIGKILL)
	if err := process.Signal(syscall.SIGKILL); err != nil {
		return false, fmt.Errorf("无法发送SIGKILL信号: %w", err)
	}

	// 再等待一下
	time.Sleep(1 * time.Second)

	// 最后检查一次
	if err := process.Signal(syscall.Signal(0)); err != nil {
		// 进程已被杀死
		return true, nil
	}

	return false, fmt.Errorf("进程仍然存在，无法杀死")
}

// killProcessWindows 在Windows系统上杀死进程
func killProcessWindows(pid int) (bool, error) {
	// 在Windows上使用taskkill命令
	cmd := exec.Command("taskkill", "/PID", strconv.Itoa(pid), "/F")
	err := cmd.Run()
	if err != nil {
		// 检查是否是因为进程不存在
		if strings.Contains(err.Error(), "not found") || strings.Contains(err.Error(), "not exist") {
			return false, nil
		}
		return false, fmt.Errorf("taskkill命令失败: %w", err)
	}
	return true, nil
}

// runBigQueryMultiDatasets 在单个线程中处理多个BigQuery数据集
func runBigQueryMultiDatasets(ctx context.Context, cfg config.Config, datasets []string) error {
	absWorkDir, err := filepath.Abs(cfg.WorkDir)
	if err != nil {
		return fmt.Errorf("获取工作目录绝对路径失败: %w", err)
	}

	// 区分认证项目和数据项目
	authProjectID := cfg.ProjectID
	dataProjectID := cfg.Database
	if dataProjectID == "" {
		dataProjectID = authProjectID
	}

	if cfg.ReadOnlyMode {
		log.Printf("[%s] 已启用只读模式", cfg.Database)
	}

	if cfg.LazyMode {
		log.Printf("[%s] 已启用懒加载模式，跳过表结构初始化", cfg.Database)
	}

	// 检查 tables 文件夹是否为空
	tablesDir := filepath.Join(absWorkDir, "tables")
	isTablesEmpty := true
	if entries, err := os.ReadDir(tablesDir); err == nil && len(entries) > 0 {
		isTablesEmpty = false
	}

	// 为每个数据集创建数据库客户端和初始化表文件
	var dbClients []db.DatabaseInterface
	for _, dataset := range datasets {
		instanceName := fmt.Sprintf("%s (%s)", dataProjectID, dataset)
		log.Printf("[%s] BigQuery实例正在初始化...", instanceName)

		dbClient, err := db.NewBigQuery(authProjectID, dataProjectID, dataset, cfg.CredentialsFile, cfg.ReadOnlyMode, cfg.ProxyURL)
		if err != nil {
			// 清理已创建的客户端
			for _, client := range dbClients {
				client.Close()
			}
			return fmt.Errorf("连接BigQuery失败 (%s): %w", dataset, err)
		}

		if cfg.Name != "" {
			dbClient.SetLogPrefix(cfg.Name)
		} else {
			dbClient.SetLogPrefix("bigquery")
		}
		dbClients = append(dbClients, dbClient)

		// 初始化表文件的逻辑
		shouldInitialize := false
		if !cfg.LazyMode {
			// 非 lazy 模式总是初始化
			shouldInitialize = true
		} else if isTablesEmpty {
			// lazy 模式下，如果 tables 文件夹为空，第一次需要初始化
			shouldInitialize = true
			log.Printf("[%s] Lazy 模式下首次运行，初始化表结构", instanceName)
		}

		if shouldInitialize {
			if err := dbClient.InitializeTableFiles(absWorkDir, cfg.IncludeTablePatterns, cfg.ExcludeTablePatterns); err != nil {
				log.Printf("[%s] 初始化表文件时出错: %v", instanceName, err)
			} else {
				log.Printf("[%s] 表文件初始化完成", instanceName)
			}
		} else if cfg.LazyMode {
			log.Printf("[%s] Lazy 模式：跳过表结构初始化（tables 文件夹不为空）", instanceName)
		}
	}

	// 确保在函数退出时关闭所有客户端
	defer func() {
		for i, client := range dbClients {
			if client != nil {
				client.Close()
				log.Printf("[%s (%s)] 数据库客户端已关闭", cfg.Database, datasets[i])
			}
		}
	}()

	// 创建单个文件监控器
	fileWatcher, err := watcher.New(absWorkDir)
	if err != nil {
		return fmt.Errorf("创建文件监控失败: %w", err)
	}
	globalWatchers[cfg.Database] = fileWatcher
	defer fileWatcher.Close()

	// 文件事件处理函数
	handleFileEvent := func(path string, op fsnotify.Op) {
		ext := filepath.Ext(path)
		if ext != ".sql" && ext != ".md" {
			return
		}

		// 从文件路径解析出数据集名称
		// 路径格式: workDir/tables/{dataset}/{table}/query.sql
		relPath, err := filepath.Rel(tablesDir, path)
		if err != nil {
			log.Printf("无法解析文件路径: %s", path)
			return
		}

		var datasetName string
		var tableName string
		var fileName string
		var targetClient db.DatabaseInterface
		var targetDataset string

		pathParts := strings.Split(filepath.ToSlash(relPath), "/")
		if len(pathParts) < 3 {
			targetClient = dbClients[0]
			targetDataset = datasets[0]
		} else {
			datasetName = pathParts[0]
			tableName = pathParts[1]
			fileName = pathParts[2]
			// 找到对应的数据库客户端
			for i, dataset := range datasets {
				if dataset == datasetName {
					targetClient = dbClients[i]
					targetDataset = dataset
					break
				}
			}
		}

		if targetClient == nil {
			log.Printf("未找到数据集 %s 对应的客户端", datasetName)
			return
		}

		instanceName := fmt.Sprintf("%s (%s)", dataProjectID, targetDataset)
		log.Printf("[%s] 检测到文件变动 (%s)，处理: %s", instanceName, op, path)

		// 处理Markdown文件修改
		if ext == ".md" {
			// 若 SQL 块被修改并已同步至 .sql，则等待后续 .sql 事件处理，直接返回
			if syncSQLFromMarkdown(path) {
				return
			}
			// 对所有 markdown 进行 JSON diff 生成 UPDATE
			if !cfg.ReadOnlyMode && (op&fsnotify.Write == fsnotify.Write || op&fsnotify.Create == fsnotify.Create) {
				go func() {
					if err := targetClient.ProcessJSONModification(path); err != nil {
						log.Printf("[%s] 处理JSON修改失败: %v", instanceName, err)
					} else {
						log.Printf("[%s] 成功处理JSON修改: %s", instanceName, path)
					}
				}()
			}
			return
		}

		// 处理SQL文件
		if ext == ".sql" {
			switch fileName {
			case "ddl.sql":
				if !cfg.ReadOnlyMode && (op&fsnotify.Write == fsnotify.Write || op&fsnotify.Create == fsnotify.Create) {
					go func() {
						if err := targetClient.GenerateDDLChange(path); err != nil {
							log.Printf("[%s] 生成 DDL 变更失败: %v", instanceName, err)
						}
					}()
				}
			case "insert.sql":
				if !cfg.ReadOnlyMode && (op&fsnotify.Write == fsnotify.Write || op&fsnotify.Create == fsnotify.Create) {
					go func() {
						if err := targetClient.ProcessInsertSQL(path); err != nil {
							log.Printf("[%s] 处理 insert.sql 失败: %v", instanceName, err)
						} else {
							log.Printf("[%s] 成功处理 insert.sql: %s", instanceName, path)
						}
					}()
				}
			case "query.sql":
				// 检查是否正在格式化，避免循环触发
				if db.IsFormattingFile(path) {
					log.Printf("[%s] 跳过格式化触发的文件: %s", instanceName, path)
					return
				}
				
				if !cfg.LazyMode {
					// 只在非懒加载模式下自动更新DDL文件
					go func() {
						dir := filepath.Dir(path)
						ddl, err := targetClient.GetTableDDL(tableName)
						if err != nil {
							log.Printf("[%s] 获取表 %s 的 DDL 失败: %v", instanceName, tableName, err)
						} else {
							ddlPath := filepath.Join(dir, "ddl.sql")
							if err := os.WriteFile(ddlPath, []byte(ddl), 0644); err != nil {
								log.Printf("[%s] 写入 DDL 文件失败: %v", instanceName, err)
							} else {
								log.Printf("[%s] 已更新 DDL 文件: %s", instanceName, ddlPath)
							}
						}
					}()
				}
				recordLastQueryIfSelect(path)
				if err := targetClient.ProcessSQLFile(path); err != nil {
					log.Printf("[%s] 处理SQL文件失败: %v", instanceName, err)
				} else {
					log.Printf("[%s] 成功处理文件: %s", instanceName, path)
				}
			default:
				if err := targetClient.ProcessSQLFile(path); err != nil {
					log.Printf("[%s] 处理SQL文件失败: %v", instanceName, err)
				} else {
					log.Printf("[%s] 成功处理文件: %s", instanceName, path)
				}
			}
		}
	}

	fileWatcher.SetEventHandler(handleFileEvent)

	if err := fileWatcher.Start(); err != nil {
		return fmt.Errorf("启动文件监控失败: %w", err)
	}

	log.Printf("[%s] 工作进程已启动，监控 %d 个数据集，工作目录: %s", cfg.Database, len(datasets), absWorkDir)

	// 等待context取消信号
	<-ctx.Done()
	log.Printf("[%s] 工作进程正在关闭...", cfg.Database)

	return nil
}

// runMySQLInstance 运行单个MySQL数据库的监控逻辑
func runMySQLInstance(ctx context.Context, cfg config.Config) error {
	var dbClient *db.DB
	var err error

	// 检查是否启用SSH连接
	if cfg.SSH != nil && cfg.SSH.Enable {
		dbClient, err = db.NewWithSSH(*cfg.SSH, cfg.Host, cfg.Port, cfg.User, cfg.Password, cfg.Database, cfg.ReadOnlyMode)
	} else {
		dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?parseTime=true",
			cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Database)
		dbClient, err = db.NewWithReadOnly(dsn, cfg.ReadOnlyMode)
	}
	if cfg.Name != "" {
		dbClient.SetLogPrefix(cfg.Name)
	} else {
		dbClient.SetLogPrefix("mysql")
	}
	if err != nil {
		return fmt.Errorf("连接MySQL数据库失败: %w", err)
	}
	defer dbClient.Close()
	return monitorDatabase(ctx, cfg, dbClient, cfg.Database)
}

// monitorDatabase 是通用的数据库监控循环
func monitorDatabase(ctx context.Context, cfg config.Config, dbClient db.DatabaseInterface, instanceName string) error {
	absWorkDir, err := filepath.Abs(cfg.WorkDir)
	if err != nil {
		return fmt.Errorf("获取工作目录绝对路径失败: %w", err)
	}

	if cfg.ReadOnlyMode {
		log.Printf("[%s] 已启用只读模式", instanceName)
	}

	if cfg.LazyMode {
		log.Printf("[%s] 已启用懒加载模式，跳过表结构初始化", instanceName)
	}

	fileWatcher, err := watcher.New(absWorkDir)
	if err != nil {
		return fmt.Errorf("创建文件监控失败: %w", err)
	}
	globalWatchers[instanceName] = fileWatcher
	defer fileWatcher.Close()

	handleFileEvent := func(path string, op fsnotify.Op) {
		ext := filepath.Ext(path)
		if ext != ".sql" && ext != ".md" {
			return
		}

		log.Printf("[%s] 检测到文件变动 (%s)，处理: %s", instanceName, op, path)

		// 处理Markdown文件修改 - 同步SQL 或生成UPDATE语句
		if ext == ".md" {
			// 如果 SQL 被同步，则无需继续
			if syncSQLFromMarkdown(path) {
				return
			}
			// 对任意 markdown 进行 JSON diff 生成 UPDATE
			if !cfg.ReadOnlyMode && (op&fsnotify.Write == fsnotify.Write || op&fsnotify.Create == fsnotify.Create) {
				go func() {
					if err := dbClient.ProcessJSONModification(path); err != nil {
						log.Printf("[%s] 处理JSON修改失败: %v", instanceName, err)
					} else {
						log.Printf("[%s] 成功处理JSON修改: %s", instanceName, path)
					}
				}()
			}
			return
		}

		// 处理SQL文件
		if ext == ".sql" {
			switch filepath.Base(path) {
			case "ddl.sql":
				if !cfg.ReadOnlyMode && (op&fsnotify.Write == fsnotify.Write || op&fsnotify.Create == fsnotify.Create) {
					go func() {
						if err := dbClient.GenerateDDLChange(path); err != nil {
							log.Printf("[%s] 生成 DDL 变更失败: %v", instanceName, err)
						}
					}()
				}
			case "insert.sql":
				if !cfg.ReadOnlyMode && (op&fsnotify.Write == fsnotify.Write || op&fsnotify.Create == fsnotify.Create) {
					go func() {
						if err := dbClient.ProcessInsertSQL(path); err != nil {
							log.Printf("[%s] 处理 insert.sql 失败: %v", instanceName, err)
						} else {
							log.Printf("[%s] 成功处理 insert.sql: %s", instanceName, path)
						}
					}()
				}
			case "query.sql":
				// 检查是否正在格式化，避免循环触发
				if db.IsFormattingFile(path) {
					log.Printf("[%s] 跳过格式化触发的文件: %s", instanceName, path)
					return
				}
				
				if !cfg.LazyMode {
					// 只在非懒加载模式下自动更新DDL文件
					go func() {
						dir := filepath.Dir(path)
						tableName := filepath.Base(dir)
						ddl, err := dbClient.GetTableDDL(tableName)
						if err != nil {
							log.Printf("[%s] 获取表 %s 的 DDL 失败: %v", instanceName, tableName, err)
						} else {
							ddlPath := filepath.Join(dir, "ddl.sql")
							if err := os.WriteFile(ddlPath, []byte(ddl), 0644); err != nil {
								log.Printf("[%s] 写入 DDL 文件失败: %v", instanceName, err)
							} else {
								log.Printf("[%s] 已更新 DDL 文件: %s", instanceName, ddlPath)
							}
						}
					}()
				}
				recordLastQueryIfSelect(path)
				if err := dbClient.ProcessSQLFile(path); err != nil {
					log.Printf("[%s] 处理SQL文件失败: %v", instanceName, err)
				} else {
					log.Printf("[%s] 成功处理文件: %s", instanceName, path)
				}
			default:
				if err := dbClient.ProcessSQLFile(path); err != nil {
					log.Printf("[%s] 处理SQL文件失败: %v", instanceName, err)
				} else {
					log.Printf("[%s] 成功处理文件: %s", instanceName, path)
				}
			}
		}
	}

	fileWatcher.SetEventHandler(handleFileEvent)

	if err := fileWatcher.Start(); err != nil {
		return fmt.Errorf("启动文件监控失败: %w", err)
	}

	log.Printf("[%s] 工作进程已启动，工作目录: %s", instanceName, absWorkDir)

	<-ctx.Done()

	return nil
}

// helper to position prompt at bottom
func showPrompt() {
	if useANSI {
		// Move cursor to bottom of screen
		fmt.Print("\033[999B\r") // down many lines then CR
		fmt.Print("\033[K")      // clear line
		fmt.Printf("%s%s> %s", Bold, Cyan, Reset)
	} else {
		fmt.Print("> ")
	}
}
